--
-- @Author:			
-- @DateTime:	2019-03-30 23:05:48
-- @Description: 消息协议的封包与解包

local skynet = require("skynet")
local cjson = require("cjson")
local wsnetpack = require("websocketnetpack")
local netpack = require("skynet.netpack")
local socket = require("skynet.socket")
local ProtoLoader = require("ProtoLoader")
local ProtoMessage = require("ProtoMessage")

--消息打包类
local MessagePack = class("MessagePack")


function MessagePack:ctor()
	self.proto_loader = nil
	self.msg_head_size = 10
	self.msg_version = 1
	self.msg_proto_type = 1 --1=proto 2=json
	self.msg_check_code = 1 --校验码
	self.msg_ext = 0 --预留

	self:loadProto()
end

--proto的加载
function MessagePack:loadProto(folder_list)
	self.proto_loader = ProtoLoader.new(folder_list)	
end



-- 设置网络消息协议头
function MessagePack:setHeader()
	--size = [1,1,4,3] 头大小,协议版本号,协议类型,数据校验码
	local str = ""
	str = str .. string.pack(">H", self.msg_head_size)
	str = str .. string.pack(">B", self.msg_version)
	str = str .. string.pack(">B", self.msg_proto_type)	
	str = str .. string.pack(">I4", self.msg_check_code)
	str = str .. string.pack(">H", self.msg_ext)	
	return str
end

--获取网络消息协议头
function MessagePack:getHeader(message)
	
	if string.len(message) < self.msg_head_size then 
		print("############ MessagePack:getHeader invalid message_size " .. string.len(message))
		return 
	end
	return {        
		msg_head_size 	= string.unpack(">H", message:sub(1,2)),
		msg_version 	= string.unpack(">B", message:sub(3,3)),
		msg_proto_type 	= string.unpack(">B", message:sub(4,4)),
		msg_check_code 	= string.unpack(">I4", message:sub(5,8)),
		msg_ext 		= string.unpack(">H", message:sub(9,10)),
	}

end

--打包网络消息
function MessagePack:packClient(msg_name, msg_body)
	local message_id = ProtoMessage.name_list[msg_name]
	local proto_head = "" .. string.pack(">H", message_id) 
	local proto_data = self.proto_loader:encode(msg_name, msg_body)
	local pack_data = self:setHeader() .. proto_head .. proto_data
	return pack_data
end


--解包网络消息
function MessagePack:unpackClient(message_buf, message_size)
	if not message_size then
		message_size = #message_buf 
	end
	if message_size < self.msg_head_size then
		log.error("############ unpack invalid message_size ".. message_size)
		return 
	end
	local message
	if type(message_buf) == 'string' then 
		message = message_buf
	else
		message = skynet.tostring(message_buf, message_size)  
		-- skynet.trash(message_buf, message_size) --释放内存
	end	
	local header = self:getHeader(message)
	--消息头的校验
	if header.msg_head_size ~= self.msg_head_size then 
		return 
	end
	local message_id =  string.unpack(">H", message:sub(self.msg_head_size + 1, self.msg_head_size + 2))
	message_id = tonumber(message_id)
	local message_name = ProtoMessage[message_id]
	message_buf = message:sub(self.msg_head_size + 3)
	local message_body = self.proto_loader:decode(message_name, message_buf)	
	if not message_body then 
		return
	end
	-- debug_log("_________", message_body)
	return message_id, message_name, message_body
end


--写入socket
function MessagePack:send(fd, conn_type, msg_name, msg_body)
	local msg = self:packClient(msg_name, msg_body)
	if not msg then 
		return 
	end
	local tmpmsg, sz
	if conn_type and conn_type == "websocket" then
		tmpmsg, sz = wsnetpack.pack(msg)
	else
		tmpmsg, sz = netpack.pack(msg)
	end
	if not tmpmsg or not sz then 
		error_log('send error tmpmsg=nil or sz=nil')
		return false
	end
	local ok, err = xpcall(socket.write, debug.traceback, fd, tmpmsg, sz)
	if not ok then
		error_log('send faild:', err)
		return false
	end
	return true
end


function MessagePack:sendJson()
	-- body
end




return MessagePack
